﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;

namespace TheGame
{
    //AbeControl definisce l'automa per la gestione del sistema
    //di controllo del personaggio principale
    //[pp.43]
    public class AbeControl
    {
        #region VARS
        public Game1 game;
        PRECONDITIONa precond = null;
        public bool FINISHEDExecution = false;
        public bool FINISHEDTransition = true;
        public Abe Abe;
        public STATEa CURRENT_STATE;
        public STATEa PREV_STATE;

        public STATEa WAIT;
        public STATEa PULLEVER;
        public STATEa DEACTIVATEBOMB;
        public STATEa ACTIVATEBOMB;
        public STATEa DEACTIVATEBOMBFAIL;
        public STATEa WAITCROUCH;
        public STATEa HUNG;
        public STATEa HUNGLONG;
        public STATEa WALK;
        public STATEa SNEAK;
        public STATEa JUMP;
        public STATEa RUN;
        public STATEa RUNSTART;
        public STATEa RUNSTOP;
        public STATEa RUNJUMP;
        public STATEa ROLL;
        public STATEa DIED;
        public STATEa GODOWN;
        public STATEa OMM;
        public STATEa NOTCONTROL;
        public STATEa ENTERDOOR;
        public STATEa EXITDOOR;


        public PRECONDITIONSa PRECONDITIONS;
        public ACTIONSa ACTIONS;

        List<string> colTypes = new List<string>();
        public Slig sligToControl = null;
        public bool DOORENTERED = false;
        public Collision DOOR = null;
        public float ALPHA = 1f; 
        #endregion

        public AbeControl() { }
        public AbeControl(Abe Abe, Game1 game)
        {
            this.game = game;
            this.Abe = Abe;

            PRECONDITIONS = new PRECONDITIONSa(this);
            ACTIONS = new ACTIONSa(this);
            
            DIED = new STATEa("DIED", this);
            WAIT = new STATEa("WAIT", this);
            PULLEVER = new STATEa("PULLEVER", this);
            DEACTIVATEBOMB = new STATEa("DEACTIVATEBOMB", this);
            ACTIVATEBOMB = new STATEa("ACTIVATEBOMB", this);
            DEACTIVATEBOMBFAIL = new STATEa("DEACTIVATEBOMBFAIL", this);
            WALK = new STATEa("WALK", this);
            SNEAK = new STATEa("SNEAK", this);
            JUMP = new STATEa("JUMP", this);
            HUNG = new STATEa("HUNG", this);
            HUNGLONG = new STATEa("HUNGLONG", this);
            RUN = new STATEa("RUN", this);
            RUNSTART = new STATEa("RUNSTART", this);
            RUNSTOP = new STATEa("RUNSTOP", this);
            RUNJUMP = new STATEa("RUNJUMP", this);
            WAITCROUCH = new STATEa("WAITCROUCH", this);
            ROLL = new STATEa("ROLL", this);
            GODOWN = new STATEa("GODOWN", this);
            OMM = new STATEa("OMM", this);
            NOTCONTROL = new STATEa("NOTCONTROL", this);
            ENTERDOOR = new STATEa("ENTERDOOR", this);
            EXITDOOR = new STATEa("EXITDOOR", this);


            WAIT.LinkTO(GODOWN).addPRECONDITION(PRECONDITIONS.GODOWN);
            WAIT.LinkTO(PULLEVER).addPRECONDITION(PRECONDITIONS.LEVA);
            WAIT.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.HELLO, ACTIONS.HELLO);
            WAIT.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.FOLLOW, ACTIONS.FOLLOW);
            WAIT.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.WAITME, ACTIONS.WAITME);
            WAIT.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.COMMANDJUMP, ACTIONS.COMMANDJUMP);
            WAIT.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.COMMANDRUNJUMP, ACTIONS.COMMANDRUNJUMP);
            WAIT.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.BLOCK, PRECONDITIONS.RIGHT), ACTIONS.BLOCK);
            WAIT.LinkTO(HUNG).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.DOWN,PRECONDITIONS.HOIST), ACTIONS.HOISTDOWN);
            WAIT.LinkTO(HUNG).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.DOWN, PRECONDITIONS.HOISTTURN), ACTIONS.AND(ACTIONS.TURN,ACTIONS.HOISTDOWN));
            WAIT.LinkTO(WAITCROUCH).addPRECONDITION(PRECONDITIONS.DOWN, ACTIONS.CROUCH);
            WAIT.LinkTO(WALK).addPRECONDITION(PRECONDITIONS.RIGHT, ACTIONS.PASS1);
            WAIT.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.toSNEAK, PRECONDITIONS.BLOCK), ACTIONS.BLOCK);
            WAIT.LinkTO(SNEAK).addPRECONDITION(PRECONDITIONS.toSNEAK, ACTIONS.SNEAK1);
            WAIT.LinkTO(RUNSTART).addPRECONDITION(PRECONDITIONS.toRUN, ACTIONS.RUN1);
            WAIT.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.toTURN, ACTIONS.TURN);
            WAIT.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.toJUMP, PRECONDITIONS.BLOCK), ACTIONS.AND(ACTIONS.KO, ACTIONS.GETUP));
            WAIT.LinkTO(ENTERDOOR).addPRECONDITION(PRECONDITIONS.ENTERDOOR);
            WAIT.LinkTO(JUMP).addPRECONDITION(PRECONDITIONS.toJUMP, ACTIONS.JUMP1);
            WAIT.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.AND(PRECONDITIONS.notAPPIGLIO,PRECONDITIONS.NOTDOOR), PRECONDITIONS.UP), ACTIONS.AND(ACTIONS.JUMPUP, ACTIONS.JUMPDOWN));
            WAIT.LinkTO(HUNG).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.AND(PRECONDITIONS.APPIGLIO, PRECONDITIONS.NOTDOOR), PRECONDITIONS.UP), ACTIONS.JUMPUP);
            WAIT.LinkTO(HUNG).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.AND(PRECONDITIONS.APPIGLIOTURN, PRECONDITIONS.NOTDOOR), PRECONDITIONS.UP), ACTIONS.AND(ACTIONS.TURN, ACTIONS.JUMPUP));
            WAIT.LinkTO(OMM).addPRECONDITION(PRECONDITIONS.ZERO);

            ENTERDOOR.LinkTO(EXITDOOR).addPRECONDITION(PRECONDITIONS.DOORENTERED);
            EXITDOOR.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.ENDSTATE);

            PULLEVER.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.ENDLEVA);

            OMM.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.SHOCK,ACTIONS.AND(ACTIONS.KO,ACTIONS.GETUP));
            OMM.LinkTO(NOTCONTROL).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ENDSTATE,PRECONDITIONS.SLIGFORCONTROL));
            OMM.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.ZEROUP);

            WALK.LinkTO(DIED).addPRECONDITION(PRECONDITIONS.BOMB,ACTIONS.EXPLODE);
            WALK.LinkTO(GODOWN).addPRECONDITION(PRECONDITIONS.GODOWN);
            WALK.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.STOP, ACTIONS.STOP);
            WALK.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.BLOCK, ACTIONS.BLOCK);           
            WALK.LinkTO(SNEAK).addPRECONDITION(PRECONDITIONS.toSNEAK);
            WALK.LinkTO(RUNSTART).addPRECONDITION(PRECONDITIONS.toRUN);

            SNEAK.LinkTO(GODOWN).addPRECONDITION(PRECONDITIONS.GODOWN);
            SNEAK.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.toSTOPSNEAK, ACTIONS.STOPSNEAK);            
            SNEAK.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.BLOCK, ACTIONS.BLOCK);            
            SNEAK.LinkTO(WALK).addPRECONDITION(PRECONDITIONS.RIGHT);
            
            JUMP.LinkTO(GODOWN).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ENDSTATE,PRECONDITIONS.GODOWN));
            JUMP.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.ENDSTATE, ACTIONS.JUMP4);
            JUMP.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.BLOCK, ACTIONS.AND(ACTIONS.KO, ACTIONS.GETUP));
                       
            GODOWN.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.NOTHOIST,PRECONDITIONS.ENDSTATE),ACTIONS.PLANE);
            GODOWN.LinkTO(HUNG).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.HOIST, PRECONDITIONS.ENDSTATE), ACTIONS.HUNGLONG);

            HUNGLONG.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.UP, ACTIONS.HOISTUP);
            HUNGLONG.LinkTO(HUNG).addPRECONDITION(PRECONDITIONS.ENDSTATE);

            HUNG.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.DOWN, ACTIONS.JUMPDOWN);
            HUNG.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.UP, ACTIONS.HOISTUP);
        
            RUNSTART.LinkTO(GODOWN).addPRECONDITION(PRECONDITIONS.GODOWN);
            RUNSTART.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.BLOCK, ACTIONS.AND(ACTIONS.KO, ACTIONS.GETUP));
            RUNSTART.LinkTO(RUN).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.toRUN, PRECONDITIONS.ENDSTATE));
            RUNSTART.LinkTO(RUNSTOP).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ENDSTATE,PRECONDITIONS.toSTOPRUN));
            RUNSTART.LinkTO(RUNSTOP).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ENDSTATE, PRECONDITIONS.STOP));
            RUNSTART.LinkTO(RUNJUMP).addPRECONDITION(PRECONDITIONS.toJUMP);
            
            RUN.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.BLOCK, ACTIONS.AND(ACTIONS.KO, ACTIONS.GETUP));
            RUN.LinkTO(GODOWN).addPRECONDITION(PRECONDITIONS.GODOWN);
            RUN.LinkTO(WALK).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.RIGHT, PRECONDITIONS.RUNOK));
            RUN.LinkTO(RUNSTOP).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.toSTOPRUN, PRECONDITIONS.RUNOK));
            RUN.LinkTO(RUNSTOP).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.STOP, PRECONDITIONS.RUNOK));
            RUN.LinkTO(RUNJUMP).addPRECONDITION(PRECONDITIONS.toJUMP);

            RUNJUMP.LinkTO(HUNGLONG).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.HOIST,PRECONDITIONS.NOTGODOWN),ACTIONS.HUNGLONG);
            RUNJUMP.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.BLOCK, ACTIONS.AND(ACTIONS.KO, ACTIONS.GETUP));
            RUNJUMP.LinkTO(RUNSTOP).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ENDSTATE, PRECONDITIONS.toSTOPRUN),ACTIONS.STOPRUNJUMP);
            RUNJUMP.LinkTO(RUN).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ENDSTATE, PRECONDITIONS.toRUN), ACTIONS.STOPRUNJUMP);
            //RUNJUMP.LinkTO(RUNSTOP).addPRECONDITION(PRECONDITIONS.ENDSTATE, ACTIONS.STOPRUNJUMP);

            RUNSTOP.LinkTO(GODOWN).addPRECONDITION(PRECONDITIONS.GODOWN);
            RUNSTOP.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.ENDSTATE);              
            RUNSTOP.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.BLOCK, ACTIONS.AND(ACTIONS.KO, ACTIONS.GETUP));

            WAITCROUCH.LinkTO(DEACTIVATEBOMB).addPRECONDITION(PRECONDITIONS.BOMBOK);
            WAITCROUCH.LinkTO(DEACTIVATEBOMB).addPRECONDITION(PRECONDITIONS.BOMBFAIL);
            WAITCROUCH.LinkTO(ACTIVATEBOMB).addPRECONDITION(PRECONDITIONS.BOMBACTIVATE);
            WAITCROUCH.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.BLOCK, PRECONDITIONS.RIGHT), ACTIONS.AND(ACTIONS.KO, ACTIONS.GETUP));
            WAITCROUCH.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.UP, ACTIONS.STANDUP);
            WAITCROUCH.LinkTO(HUNG).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.DOWN, PRECONDITIONS.HOIST), ACTIONS.HOISTDOWN);
            WAITCROUCH.LinkTO(ROLL).addPRECONDITION(PRECONDITIONS.RIGHT, ACTIONS.ROLL1);
            WAITCROUCH.LinkTO(WAITCROUCH).addPRECONDITION(PRECONDITIONS.toTURN, ACTIONS.TURNDOWN);

            ACTIVATEBOMB.LinkTO(WAITCROUCH).addPRECONDITION(PRECONDITIONS.ENDBOMB);

            DEACTIVATEBOMB.LinkTO(DIED).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.ENDSTATE,PRECONDITIONS.BOMBACTIVE));
            DEACTIVATEBOMB.LinkTO(WAITCROUCH).addPRECONDITION(PRECONDITIONS.ENDSTATE);

            ROLL.LinkTO(GODOWN).addPRECONDITION(PRECONDITIONS.GODOWN);
            ROLL.LinkTO(WAITCROUCH).addPRECONDITION(PRECONDITIONS.STOP);
            ROLL.LinkTO(WAIT).addPRECONDITION(PRECONDITIONS.AND(PRECONDITIONS.BLOCK,PRECONDITIONS.RIGHT), ACTIONS.AND(ACTIONS.KO, ACTIONS.GETUP));
            ROLL.LinkTO(SNEAK).addPRECONDITION(PRECONDITIONS.toSNEAK);
            ROLL.LinkTO(RUN).addPRECONDITION(PRECONDITIONS.toRUN);

            CURRENT_STATE = WAIT;
            PREV_STATE = CURRENT_STATE;

        }

        //Esegue l'automa definito nel costruttore di AbeControl
        //Viene chiamato nel metodo Update della classe Game1
        //[pp.48,49]
        public void ROUTINE()
        {
            //if (CURRENT_STATE.name != "DIED")
            //{
            #region ColorMask
            if (CURRENT_STATE == WALK || CURRENT_STATE == RUN || CURRENT_STATE == ROLL || CURRENT_STATE == JUMP)
                Abe.AbeNoise = true;
            else
                Abe.AbeNoise = false;

            colTypes = game.CurrentLevel.collision(Abe);

            if (colTypes.Contains(COLLISIONS.GRAYAREA))
            {
                Abe.color = Color.DarkSlateGray;
                foreach (Slig slig in game.CurrentLevel.Sligs)
                {
                    slig.SligEye.Height = 10;
                    slig.SligEye.Width = slig.EYE_CAPACITY;
                    slig.SligEye.X = slig.boundingBox.X + slig.boundingBox.Width / 2 + ((slig.EYE_CAPACITY / 2) * (slig.Direction - 1));
                    slig.SligEye.Y = slig.boundingBox.Y;
                }

            }
            if (colTypes.Contains(COLLISIONS.BLACKAREA))
            {
                Abe.color = Color.Black;
                foreach (Slig slig in game.CurrentLevel.Sligs)
                {
                    if (!slig.AI.ABE_DETECTED)
                    {
                        slig.SligEye.X = 0;
                        slig.SligEye.Y = 0;
                        slig.SligEye.Height = 0;
                        slig.SligEye.Width = 0;
                    }
                }
            }
            if (!colTypes.Contains(COLLISIONS.GRAYAREA) & !colTypes.Contains(COLLISIONS.BLACKAREA))
            {
                Abe.color = Color.White;
                foreach (Slig slig in game.CurrentLevel.Sligs)
                {
                    slig.SligEye.Height = 10;
                    slig.SligEye.Width = slig.EYE_CAPACITY;
                    slig.SligEye.X = slig.boundingBox.X + slig.boundingBox.Width / 2 + ((slig.EYE_CAPACITY / 2) * (slig.Direction - 1));
                    slig.SligEye.Y = slig.boundingBox.Y;
                }
            }
            if (colTypes.Contains(COLLISIONS.ELECTRO))
            {
                if (ALPHA > 0)
                    ALPHA -= 0.05f;
                Abe.color = new Color(254, 255, 255, ALPHA);

                if (ALPHA <= 0)
                {
                    CURRENT_STATE = DIED;
                    Abe.DEAD = true;
                }


            } 
            #endregion
                //La transizione da questi stati può avvenire in qualsiasi momento
                if (CURRENT_STATE == WAIT || CURRENT_STATE == HUNG || CURRENT_STATE == HUNGLONG || CURRENT_STATE == WAITCROUCH)
                {
                    #region HandleStateTransition
                    if (FINISHEDTransition)
                    {
                        precond = CURRENT_STATE.TryChangeState();
                        FINISHEDExecution = CURRENT_STATE.Execute();
                        if (FINISHEDExecution)
                        {
                            CURRENT_STATE.AnimsTODO[CURRENT_STATE.CURRENT_ANIM].Reset();
                            PREV_STATE = CURRENT_STATE;
                        }
                    }
                    if (precond != null)
                    {
                        if (precond.ACTION != null)
                        {
                            FINISHEDTransition = precond.ACTION.DO();
                            CURRENT_STATE.CURRENTACTION = precond.ACTION.NAME;
                        }

                        if (FINISHEDTransition)
                        {
                            CURRENT_STATE.CURRENTACTION = "null";
                            CURRENT_STATE = precond.ARC.TO;
                            CURRENT_STATE.ENDSTATE = false;
                            if (precond.ACTION != null)
                                Abe.SAYS = precond.ACTION.NAME;
                        }
                    } 
                    #endregion
                }
                else//Tutti gli altri stati esigono che tutte le animazione contenute siano state eseguite 
                {
                    //L'arco è stato percorso, esegue lo stato corrente
                    if (FINISHEDTransition)
                    {
                        if (FINISHEDExecution)
                            precond = CURRENT_STATE.TryChangeState();
                        if (precond != null)
                            FINISHEDExecution = true;
                        else
                            FINISHEDExecution = CURRENT_STATE.Execute();
                    }
                    //Tutte le animazione sono state seguite
                    if (FINISHEDExecution)
                    {
                        CURRENT_STATE.AnimsTODO[CURRENT_STATE.CURRENT_ANIM].Reset();
                        PREV_STATE = CURRENT_STATE;
                        if (FINISHEDTransition & precond == null)
                            precond = CURRENT_STATE.TryChangeState();//Controllo precondizioni

                        if (precond != null)//Almeno una precondizione è stata verificata
                        {
                            if (precond.ACTION != null)//Se una precondizione ha associata un'azione
                                FINISHEDTransition = precond.ACTION.DO();//L'azione viene eseguita
                            if (FINISHEDTransition)
                            {
                                CURRENT_STATE = precond.ARC.TO;//L'automa transita nello stato successivo
                                CURRENT_STATE.ENDSTATE = false;
                                precond = null;
                            }
                        }
                    }
                }
            //}
        }
    }




    //Definisce gli stati dell'automa
    //Ogni stato contiene una o più animazioni da eseguire
    //[p.45]
    public class STATEa
    {
        public bool ENDSTATE;
        public List<ARCa> ARCS;
        public List<Animation> AnimsTODO;
        public int CURRENT_ANIM = 0;
        public string CURRENTACTION = "null";
        public string name;
        public AbeControl Control;
        public STATEa(string name, AbeControl Control)
        {
            this.Control = Control;
            this.name = name;
            ENDSTATE = false;
            AnimsTODO = new List<Animation>();
            ARCS = new List<ARCa>();

            if (name == "ENTERDOOR")
            {
                AnimsTODO.Add(Control.Abe.ENTERDOOR);
            }
            if (name == "EXITDOOR")
            {
                AnimsTODO.Add(Control.Abe.EXITDOOR);
                //AnimsTODO.Add(Control.Abe.WAIT);
            }
            if (name == "PULLEVER")
            {
                AnimsTODO.Add(Control.Abe.PULLEVER);
            }
            if (name == "ACTIVATEBOMB")
            {
                AnimsTODO.Add(Control.Abe.BOMBDEACTIVATE);
            }
            if (name == "DEACTIVATEBOMB")
            {
                AnimsTODO.Add(Control.Abe.BOMBDEACTIVATE);
            }
            if (name == "DEACTIVATEBOMBFAIL")
            {
                AnimsTODO.Add(Control.Abe.BOMBDEACTIVATEFAIL);
            }
            if (name == "WAIT")
            {
                AnimsTODO.Add(Control.Abe.WAIT);
            }
            if (name == "WAITCROUCH")
            {
                AnimsTODO.Add(Control.Abe.WAITcROUCH);
            }
            if (name == "HUNG")
            {
                AnimsTODO.Add(Control.Abe.HUNG);
            }
            if (name == "HUNGLONG")
            {
                AnimsTODO.Add(Control.Abe.HUNGLONG);
            }
            if (name == "GODOWN")
            {
                AnimsTODO.Add(Control.Abe.GODOWN);
            }

            if (name == "WALK")
            {
                AnimsTODO.Add(Control.Abe.PASS_2);
                AnimsTODO.Add(Control.Abe.PASS_3);
            }

            if (name == "SNEAK")
            {
                AnimsTODO.Add(Control.Abe.SNEAK_2);
                AnimsTODO.Add(Control.Abe.SNEAK_3);
            }

            if (name == "JUMP")
            {
                AnimsTODO.Add(Control.Abe.JUMP_2);
                AnimsTODO.Add(Control.Abe.JUMP_3);
            }
            if (name == "RUN")
            {               
                AnimsTODO.Add(Control.Abe.RUN_4);
                AnimsTODO.Add(Control.Abe.RUN_5);
                AnimsTODO.Add(Control.Abe.RUN_2);
                AnimsTODO.Add(Control.Abe.RUN_3);
            }
            if (name == "RUNSTOP")
            {
                AnimsTODO.Add(Control.Abe.RUNsTOP_1);
                AnimsTODO.Add(Control.Abe.RUNsTOP_2);
            }
            if (name == "RUNJUMP")
            {
                AnimsTODO.Add(Control.Abe.RUNJUMP1);
                AnimsTODO.Add(Control.Abe.RUNJUMP2);
                AnimsTODO.Add(Control.Abe.RUNJUMP3);
                //AnimsTODO.Add(Control.Abe.RUNJUMP4);
            }
            if (name == "RUNSTART")
            {
                AnimsTODO.Add(Control.Abe.RUN_2);
                AnimsTODO.Add(Control.Abe.RUN_3);
            }
            if (name == "ROLL")
            {
                AnimsTODO.Add(Control.Abe.ROLL2);
                AnimsTODO.Add(Control.Abe.ROLL3);
            }
            if (name == "OMM")
            {
                AnimsTODO.Add(Control.Abe.OMM);
                AnimsTODO.Add(Control.Abe.OMM);
                AnimsTODO.Add(Control.Abe.OMM);
                AnimsTODO.Add(Control.Abe.OMM);
                AnimsTODO.Add(Control.Abe.OMM);
                AnimsTODO.Add(Control.Abe.OMM);
            }
            if (name == "NOTCONTROL")
            {
                AnimsTODO.Add(Control.Abe.NOTCONTROL);
            }
            if (name == "DIED")
            {
                AnimsTODO.Add(Control.Abe.DIE);
            }
            if (name != "DIED")
            {
                this.LinkTO(Control.DIED).addPRECONDITION(Control.PRECONDITIONS.DIED);
                //this.LinkTO(Control.DIED).addPRECONDITION(Control.PRECONDITIONS.WARN, Control.ACTIONS.DIE);
            }
        }

        //Collega due stati e restituisce l'arco associato
        public ARCa LinkTO(STATEa to)
        {
            ARCa arc = new ARCa(this.name + "to" + to.name, this, to);

            foreach (ARCa arcNew in ARCS)
            {
                if (arcNew.NAME == arc.NAME)
                    return arcNew;
            }

            this.ARCS.Add(arc);
            return arc;
        }

        //Esegue tutte le animazioni contenute nello stato corrente
        public bool Execute()
        {
            if (!AnimsTODO[CURRENT_ANIM].LastFrameDone)
            {
                Control.Abe.AnimateAbe(AnimsTODO[CURRENT_ANIM]);
                return false;
            }
            else
            {
                if (CURRENT_ANIM == AnimsTODO.Count - 1)
                {
                    ENDSTATE = true;
                    CURRENT_ANIM = 0;
                }
                else
                {
                    CURRENT_ANIM++;
                }
                
                return true;
            }
        }

        //Controlla le precondizioni di tutti gli archi uscenti
        public PRECONDITIONa TryChangeState()
        {
            foreach (ARCa arc in Control.CURRENT_STATE.ARCS)
            {
                foreach (PRECONDITIONa precondition in arc.PRECONDITIONS)
                {
                    if (precondition.Verify())
                        return precondition;
                }
            }
            return null;
        }
    }

    //Definisce gli archi dell'automa
    //[p.47]
    public class ARCa
    {
        string name;
        STATEa from;
        STATEa to;    

        List<PRECONDITIONa> preconditions;

        public ARCa(string name, STATEa from, STATEa to)
        {
            preconditions = new List<PRECONDITIONa>();
            this.name = name;
            this.from = from;
            this.to = to;
        }

        //Pone una precondizione sull'arco
        //[p.47]
        public void addPRECONDITION(PRECONDITIONa precondition)
        {
            PRECONDITIONa p = new PRECONDITIONa(from.Control, precondition.NAME);
            p.prec1 = precondition.prec1;
            p.prec2 = precondition.prec2;
            preconditions.Add(p);
            p.ARC = this;
        }

        //Pone una precondizione e un'azione sull'arco
        //Se la precondizione è verificata, viene eseguita l'azione
        //[p.47]
        public void addPRECONDITION(PRECONDITIONa precondition, ACTIONa action)
        {
            PRECONDITIONa p = new PRECONDITIONa(from.Control, precondition.NAME);
            p.prec1 = precondition.prec1;
            p.prec2 = precondition.prec2;
            preconditions.Add(p);
            p.addACTION(action);
            p.ARC = this;
        }

        #region Attribute
        public string NAME
        {
            get { return name; }
        }

        public List<PRECONDITIONa> PRECONDITIONS
        {
            get { return preconditions; }
        }

        public STATEa FROM
        {
            get { return from; }
        }

        public STATEa TO
        {
            get { return to; }
        } 
        #endregion

    }


    //Definisce le precondizioni che devono essere aggiunte ad un arco per transitare da uno stato all'altro.
    //[p.46]
    public class PRECONDITIONa
    {
        string name;
        AbeControl Control;
        ACTIONa action;
        ARCa arc;
        public PRECONDITIONa prec1;
        public PRECONDITIONa prec2;
        public PRECONDITIONa(AbeControl Control, string name)
        {
            this.name = name;
            this.Control = Control;
        }

        public void addACTION(ACTIONa action)
        {
            this.action = action;
        }

        //Controlla se la precondizione è soddisfatta
        public bool Verify()
        {
            if (name == "RIGHT")
            {
                if (((Control.game.rightDown & Control.Abe.Direction == 1) || (Control.game.leftDown & Control.Abe.Direction == -1)) & !Control.game.altDown & !Control.game.shiftDown) 
                    return true;
            }

            if (name == "DOORENTERED")
            {
                if (Control.CURRENT_STATE ==  Control.ENTERDOOR && Control.CURRENT_STATE.ENDSTATE)
                {
                    Control.DOORENTERED = true;
                    return true;
                }
            }
            if (name == "ENTERDOOR")
            {
                if (Control.game.upDown)
                {
                    List<Collision> colls = new List<Collision>();

                    colls = Control.game.CurrentLevel.GetCollision(Control.Abe);

                    foreach (Collision coll in colls)
                    {
                        if (coll.TYPE == COLLISIONS.DOOR)
                        {
                            Control.DOOR = coll;
                            return true;
                        }
                    }
                }
            }
            if (name == "NOTDOOR")
            {
                List<string> colTypes = new List<string>();

                colTypes = Control.game.CurrentLevel.collision(Control.Abe);
                if (!colTypes.Contains(COLLISIONS.DOOR))
                    return true;
            }

            if (name == "LEVA")
            {
                List<string> colTypes = new List<string>();

                colTypes = Control.game.CurrentLevel.collision(Control.Abe);
                if (Control.Abe.CURRENTOBJECTA != null && (colTypes.Contains(COLLISIONS.LEVA)))
                {
                    if (Control.game.CTRLDown)
                    {

                        Control.Abe.CURRENTOBJECTA.objControl.ACTIVE = true;
                        foreach (ObjectA slave in Control.Abe.CURRENTOBJECTA.SLAVES)
                        {
                            slave.objControl.ACTIVE = true;
                            slave.objControl.ELECTRO_ON = !slave.objControl.ELECTRO_ON;
                        }

                        return true;
                    }
                    else
                    {
                        foreach (ObjectA slave in Control.Abe.CURRENTOBJECTA.SLAVES)
                            slave.objControl.ACTIVE = false;
                    }                     
                }
            }

            if (name == "BOMBACTIVE")
            {
                List<string> colTypes = new List<string>();

                colTypes = Control.game.CurrentLevel.collision(Control.Abe);
                if (Control.Abe.CURRENTOBJECTA != null && colTypes.Contains(COLLISIONS.BOMBINNESCO) && Control.Abe.CURRENTOBJECTA.objControl.ACTIVE)
                {
                    Control.Abe.DEAD = true; 
                    return true; 
                }
            }

            if (name == "BOMBACTIVATE")
            {
                List<string> colTypes = new List<string>();

                colTypes = Control.game.CurrentLevel.collision(Control.Abe);
                if ((Control.Abe.CURRENTOBJECTA != null && colTypes.Contains(COLLISIONS.BOMBINNESCO)))
                {
                    if (Control.game.CTRLDown & !Control.Abe.CURRENTOBJECTA.objControl.ACTIVE)
                    {
                        return true;
                    }
                }
            }
            if (name == "BOMBOK")
            {
                List<string> colTypes = new List<string>();

                colTypes = Control.game.CurrentLevel.collision(Control.Abe);
                if ((Control.Abe.CURRENTOBJECTA != null && Control.Abe.CURRENTOBJECTA.objControl.ACTIVE && colTypes.Contains(COLLISIONS.BOMBINNESCO)))
                {
                    int fromBip = Math.Abs(9 - Control.Abe.CURRENTOBJECTA.objControl.CURRENT_STATE.AnimsTODO[Control.Abe.CURRENTOBJECTA.objControl.CURRENT_STATE.CURRENT_ANIM].CurrentFrame);
                    if (Control.game.CTRLDown & fromBip <= Control.Abe.CURRENTOBJECTA.RangeInnesco)
                    {
                        Control.Abe.CURRENTOBJECTA.objControl.ACTIVE = false;
                        return true;
                    }
                }
            }

            if (name == "BOMBFAIL")
            {
                List<string> colTypes = new List<string>();

                colTypes = Control.game.CurrentLevel.collision(Control.Abe);
                if ((Control.Abe.CURRENTOBJECTA != null && Control.Abe.CURRENTOBJECTA.objControl.ACTIVE && colTypes.Contains(COLLISIONS.BOMBINNESCO)))
                {
                    int fromBip = Math.Abs(9 - Control.Abe.CURRENTOBJECTA.objControl.CURRENT_STATE.AnimsTODO[Control.Abe.CURRENTOBJECTA.objControl.CURRENT_STATE.CURRENT_ANIM].CurrentFrame);
                    if (Control.game.CTRLDown & fromBip > Control.Abe.CURRENTOBJECTA.RangeInnesco)
                    {
                        Control.Abe.CURRENTOBJECTA.objControl.ACTIVE = true;
                        //Control.Abe.DEAD = true;
                        return true;
                    }
                }

            }
            if (name == "BOMB")
            {
                List<string> colTypes = new List<string>();

                colTypes = Control.game.CurrentLevel.collision(Control.Abe);
                if ((colTypes.Contains(COLLISIONS.BOMB)))
                {
                    Control.Abe.DEAD = true;
                    return true;
                }

            }

            if (name == "ENDLEVA")
            {
                if (Control.CURRENT_STATE == Control.PULLEVER && Control.PULLEVER.ENDSTATE)
                {
                    Control.Abe.CURRENTOBJECTA.objControl.ACTIVE = false;                    
                    return true;
                }
            }

            if (name == "ENDBOMB")
            {
                if (Control.CURRENT_STATE == Control.ACTIVATEBOMB && Control.ACTIVATEBOMB.ENDSTATE)
                {
                    Control.Abe.CURRENTOBJECTA.objControl.ACTIVE = true;
                    return true;
                }
            }

            if (name == "ZERO")
            {
                if (Control.game.ZeroDown)
                {
                    foreach (ObjectA obj in Control.game.CurrentLevel.ObjectsA)
                        if (obj.NAME == "OMM")
                            obj.objControl.ACTIVE = true;
                    
                    return true;
                }
            }

            if (name == "ZEROUP")
            {
                if (!Control.game.ZeroDown)
                {
                    foreach (ObjectA obj in Control.game.CurrentLevel.ObjectsA)
                        if (obj.NAME == "OMM")
                            obj.objControl.ACTIVE = false;

                    Control.OMM.CURRENT_ANIM = 0;
                    return true;
                }
            }

            if (name == "STOP")
            {
                if (((!Control.game.rightDown & Control.Abe.Direction == 1) || (!Control.game.leftDown & Control.Abe.Direction == -1)))
                    return true;
            }

            if (name == "toSNEAK")
            {
                if (((Control.game.rightDown & Control.Abe.Direction == 1) || (Control.game.leftDown & Control.Abe.Direction == -1)) & Control.game.altDown)
                    return true;
            }

            if (name == "toRUN")
            {
                if (((Control.game.rightDown & Control.Abe.Direction == 1) || (Control.game.leftDown & Control.Abe.Direction == -1)) & Control.game.shiftDown)
                    return true;
            }

            if (name == "toSTOPSNEAK")
            {
                if (((!Control.game.rightDown & Control.Abe.Direction == 1) || (!Control.game.leftDown & Control.Abe.Direction == -1)))
                    return true;
            }

            if (name == "toSTOPRUN")
            {
                //if (((!Control.game.rightDown & Control.Abe.Direction == 1) || (!Control.game.leftDown & Control.Abe.Direction == -1)))
                if(!Control.game.shiftDown)
                    return true;
            }

            if (name == "toTURN")
            {
                if ((Control.Abe.Direction == -1 & Control.game.rightDown) || (Control.Abe.Direction == 1 & Control.game.leftDown))
                    return true;
            }

            if (name == "toJUMP")
            {
                if (Control.game.spaceDown)
                    return true;
            }
            if (name == "UP")
            {
                if (Control.game.upDown)
                    return true;
            }
            if (name == "DOWN")
            {
                if (Control.game.downDown)
                    return true;

            }

            if (name == "APPIGLIO")
            {
                List<string> colTypes = new List<string>();
                
                colTypes = Control.game.CurrentLevel.collision(Control.Abe);
                if (colTypes.Contains(COLLISIONS.APPIGLIODESTRO) & Control.Abe.Direction == 1 || colTypes.Contains(COLLISIONS.APPIGLIOSINISTRO) & Control.Abe.Direction == -1)
                    return true;
            }
            if (name == "APPIGLIOTURN")
            {
                List<string> colTypes = new List<string>();

                colTypes = Control.game.CurrentLevel.collision(Control.Abe);
                if (colTypes.Contains(COLLISIONS.APPIGLIODESTRO) & Control.Abe.Direction == -1 || colTypes.Contains(COLLISIONS.APPIGLIOSINISTRO) & Control.Abe.Direction == 1)
                    return true;
            }

            if (name == "notAPPIGLIO")
            {
                List<string> colTypes = new List<string>();

                colTypes = Control.game.CurrentLevel.collision(Control.Abe);
                if (!colTypes.Contains(COLLISIONS.APPIGLIODESTRO) & !colTypes.Contains(COLLISIONS.APPIGLIOSINISTRO))
                    return true;
            }         

            if (name == "HOIST")
            {
                List<string> colTypes = new List<string>();

                colTypes = Control.game.CurrentLevel.collision(Control.Abe);
                if (colTypes.Contains(COLLISIONS.HOISTDESTRO) & Control.Abe.Direction == 1 || colTypes.Contains(COLLISIONS.HOISTSINISTRO) & Control.Abe.Direction == -1)
                    return true;
            }

            if (name == "NOTHOIST")
            {
                List<string> colTypes = new List<string>();

                colTypes = Control.game.CurrentLevel.collision(Control.Abe);
                if (!colTypes.Contains(COLLISIONS.HOISTDESTRO) & Control.Abe.Direction == 1 || !colTypes.Contains(COLLISIONS.HOISTSINISTRO) & Control.Abe.Direction == -1)
                    return true;
            }
            if (name == "HOISTTURN")
            {
                List<string> colTypes = new List<string>();

                colTypes = Control.game.CurrentLevel.collision(Control.Abe);
                if (colTypes.Contains(COLLISIONS.HOISTDESTRO) & Control.Abe.Direction == -1 || colTypes.Contains(COLLISIONS.HOISTSINISTRO) & Control.Abe.Direction == 1)
                    return true;
            }

            if (name == "BLOCK")
            {
                List<string> colTypes = new List<string>();

                colTypes = Control.game.CurrentLevel.collision(Control.Abe);
                if (colTypes.Contains(COLLISIONS.BLOCCO))
                    return true;
            }
            if (name == "GODOWN")
            {
                List<string> colTypes = new List<string>();

                colTypes = Control.game.CurrentLevel.collision(Control.Abe);
                if ((colTypes.Contains(COLLISIONS.GODOWN)))
                    return true;
            }

            if (name == "NOTGODOWN")
            {
                List<string> colTypes = new List<string>();

                colTypes = Control.game.CurrentLevel.collision(Control.Abe);
                if ((!colTypes.Contains(COLLISIONS.GODOWN)))
                    return true;
            }
            if (name == "MATTATOIO")
            {
                List<string> colTypes = new List<string>();

                colTypes = Control.game.CurrentLevel.collision(Control.Abe);
                if ((colTypes.Contains(COLLISIONS.MATTATOIO)))
                    return true;
            }

            if (name == "SHOCK")
            {
                if (Control.CURRENT_STATE.CURRENT_ANIM == 1 & Control.game.CurrentLevel.Sentinella)
                {
                    Control.OMM.CURRENT_ANIM = 0;
                    List<string> colTypes = new List<string>();

                    colTypes = Control.game.CurrentLevel.collision(Control.Abe);
                    if ((colTypes.Contains(COLLISIONS.SHOCK)))
                        return true;
                }
            }

            if (name == "ENDSTATE")
            {
                if (Control.CURRENT_STATE.ENDSTATE)
                    return true;
            }

            if (name == "SLIGFORCONTROL")
            {
                if (Control.game.CurrentLevel.Sligs.Count > 0 & Control.sligToControl == null & Control.CURRENT_STATE.ENDSTATE)
                {
                    Control.sligToControl = Control.game.CurrentLevel.Sligs[0];
                    Control.sligToControl.AI.CURRENT_STATE = Control.sligToControl.AI.POSSESSED;
                    return true;
                }
            }

            if (name == "HELLO")
            {
                if (Control.game.OneDown)
                    return true;
            }

            if (name == "FOLLOW")
            {
                if (Control.game.TwoDown)
                    return true;
            }

            if (name == "WAITME")
            {
                if (Control.game.ThreeDown)
                    return true;
            }

            if (name == "COMMANDJUMP")
            {
                if (Control.game.FourDown & !Control.game.shiftDown)
                    return true;
            }
            if (name == "COMMANDRUNJUMP")
            {
                if (Control.game.FourDown & Control.game.shiftDown)
                    return true;
            }

            if (name == "RUNOK")
            {
                if (Control.CURRENT_STATE.AnimsTODO[Control.CURRENT_STATE.CURRENT_ANIM] == Control.Abe.RUN_3 || Control.CURRENT_STATE.AnimsTODO[Control.CURRENT_STATE.CURRENT_ANIM] == Control.Abe.RUN_5)
                    return true;
            }

            if (name == "DIED")
            {
                if (Control.Abe.DEAD)
                {
                    Control.Abe.boundingBox = new Microsoft.Xna.Framework.Rectangle(Control.Abe.boundingBox.X, Control.Abe.boundingBox.Y, 0, 0);
                    return true;
                }
            }

            if (name == "AND")
            {
                return this.prec1.Verify() & this.prec2.Verify();
            }

            return false;
        }

        #region Attribute
        public ACTIONa ACTION
        {
            get { return action; }
        }
        public ARCa ARC
        {
            get { return arc; }
            set { arc = value; }
        }
        public string NAME
        {
            get { return name; }
        } 
        #endregion
    }

    //Contiene i riferimenti a tutte le istanze della classe PRECONDITIONa
    public class PRECONDITIONSa
    {
        AbeControl Control;

        public PRECONDITIONa RIGHT;
        public PRECONDITIONa toRUN;
        public PRECONDITIONa STOP;
        public PRECONDITIONa toSNEAK;
        public PRECONDITIONa toSTOPSNEAK;
        public PRECONDITIONa toSTOPRUN;
        public PRECONDITIONa toTURN;
        public PRECONDITIONa toJUMP;
        public PRECONDITIONa UP;
        public PRECONDITIONa DOWN;
        public PRECONDITIONa APPIGLIO;
        public PRECONDITIONa APPIGLIOTURN;
        public PRECONDITIONa notAPPIGLIO;
        public PRECONDITIONa ENDSTATE;
        public PRECONDITIONa BLOCK;
        public PRECONDITIONa HOIST;
        public PRECONDITIONa HOISTTURN;
        public PRECONDITIONa GODOWN;
        public PRECONDITIONa NOTGODOWN;
        public PRECONDITIONa LEVA;
        public PRECONDITIONa BOMBOK;
        public PRECONDITIONa BOMBFAIL;
        public PRECONDITIONa BOMBACTIVATE;
        public PRECONDITIONa BOMBACTIVE;
        public PRECONDITIONa BOMB;
        public PRECONDITIONa ENDLEVA;
        public PRECONDITIONa ENDBOMB;
        public PRECONDITIONa HELLO;
        public PRECONDITIONa FOLLOW;
        public PRECONDITIONa WAITME;
        public PRECONDITIONa COMMANDJUMP;
        public PRECONDITIONa COMMANDRUNJUMP;
        public PRECONDITIONa RUNOK;
        public PRECONDITIONa DIED;
        public PRECONDITIONa MATTATOIO;
        public PRECONDITIONa SHOCK;
        public PRECONDITIONa CTRL;
        public PRECONDITIONa CTRLUP;
        public PRECONDITIONa NOTHOIST;
        public PRECONDITIONa ZERO;
        public PRECONDITIONa ZEROUP;
        public PRECONDITIONa SLIGFORCONTROL;
        public PRECONDITIONa ENTERDOOR;
        public PRECONDITIONa NOTDOOR;
        public PRECONDITIONa DOORENTERED;

        public PRECONDITIONSa(AbeControl Control)
        {
            this.Control = Control;
            RIGHT = new PRECONDITIONa(Control, "RIGHT");
            toRUN = new PRECONDITIONa(Control, "toRUN");
            STOP = new PRECONDITIONa(Control, "STOP");
            toSNEAK = new PRECONDITIONa(Control, "toSNEAK");
            toSTOPSNEAK = new PRECONDITIONa(Control, "toSTOPSNEAK");
            toSTOPRUN = new PRECONDITIONa(Control, "toSTOPRUN");
            toTURN = new PRECONDITIONa(Control, "toTURN");
            toJUMP = new PRECONDITIONa(Control, "toJUMP");
            UP = new PRECONDITIONa(Control, "UP");
            DOWN = new PRECONDITIONa(Control, "DOWN");
            APPIGLIO = new PRECONDITIONa(Control, "APPIGLIO");
            APPIGLIOTURN = new PRECONDITIONa(Control, "APPIGLIOTURN");
            notAPPIGLIO = new PRECONDITIONa(Control, "notAPPIGLIO");
            ENDSTATE = new PRECONDITIONa(Control, "ENDSTATE");
            BLOCK = new PRECONDITIONa(Control, "BLOCK");
            HOIST = new PRECONDITIONa(Control, "HOIST");
            NOTHOIST = new PRECONDITIONa(Control, "NOTHOIST");
            HOISTTURN = new PRECONDITIONa(Control, "HOISTTURN");
            NOTGODOWN = new PRECONDITIONa(Control, "NOTGODOWN");
            GODOWN = new PRECONDITIONa(Control, "GODOWN");
            LEVA = new PRECONDITIONa(Control, "LEVA");
            BOMBOK = new PRECONDITIONa(Control, "BOMBOK");
            BOMBFAIL = new PRECONDITIONa(Control, "BOMBFAIL");
            BOMB = new PRECONDITIONa(Control, "BOMB");
            BOMBACTIVATE = new PRECONDITIONa(Control, "BOMBACTIVATE");
            BOMBACTIVE = new PRECONDITIONa(Control, "BOMBACTIVE");
            ENDLEVA = new PRECONDITIONa(Control, "ENDLEVA");
            ENDBOMB = new PRECONDITIONa(Control, "ENDBOMB");
            HELLO = new PRECONDITIONa(Control, "HELLO");
            FOLLOW = new PRECONDITIONa(Control, "FOLLOW");
            WAITME = new PRECONDITIONa(Control, "WAITME");
            COMMANDJUMP = new PRECONDITIONa(Control, "COMMANDJUMP");
            COMMANDRUNJUMP = new PRECONDITIONa(Control, "COMMANDRUNJUMP");
            RUNOK = new PRECONDITIONa(Control, "RUNOK");
            DIED = new PRECONDITIONa(Control, "DIED");
            MATTATOIO = new PRECONDITIONa(Control, "MATTATOIO");
            SHOCK = new PRECONDITIONa(Control, "SHOCK");
            CTRL = new PRECONDITIONa(Control, "CTRL");
            CTRLUP = new PRECONDITIONa(Control, "CTRLUP");
            ZERO = new PRECONDITIONa(Control, "ZERO");
            ZEROUP = new PRECONDITIONa(Control, "ZEROUP");
            SLIGFORCONTROL = new PRECONDITIONa(Control, "SLIGFORCONTROL");
            ENTERDOOR = new PRECONDITIONa(Control, "ENTERDOOR");
            NOTDOOR = new PRECONDITIONa(Control, "NOTDOOR");
            DOORENTERED = new PRECONDITIONa(Control, "DOORENTERED");

            
        }

        public PRECONDITIONa AND(PRECONDITIONa prec1, PRECONDITIONa prec2)
        {
            PRECONDITIONa precResult = new PRECONDITIONa(Control, "AND");
            precResult.prec1 = prec1;
            precResult.prec2 = prec2;

            return precResult;

        }
    }

    //Definisce le azioni che possono essere associate ad una precondizione
    //Ogni azione può contenere una o più animazioni.
    //[p.45]
    public class ACTIONa
    {
        AbeControl Control;
        string name;
        public List<Animation> AnimsTODO;
        int CURRENT_ANIM = 0;
        public ACTIONa action1;
        public ACTIONa action2;

        public ACTIONa(AbeControl Control, string name)
        {
            AnimsTODO = new List<Animation>();
            this.Control = Control;
            this.name = name;

            if (name == "STOP")
            {
                AnimsTODO.Add(Control.Abe.STOP);
            }
            if (name == "STOPSNEAK")
            {
                AnimsTODO.Add(Control.Abe.SNEAKsTOP);
            }
            if (name == "STOPRUNJUMP")
            {
                AnimsTODO.Add(Control.Abe.RUNJUMP4);
            }
            if (name == "HUNGLONG")
            {
                AnimsTODO.Add(Control.Abe.HUNGLONG);
            }
            if (name == "PASS1")
            {
                AnimsTODO.Add(Control.Abe.PASS_1);
            }
            if (name == "JUMP1")
            {
                AnimsTODO.Add(Control.Abe.JUMP_1);
            }
            if (name == "JUMP4")
            {
                AnimsTODO.Add(Control.Abe.JUMP_4);
            }
            if (name == "RUN1")
            {
                AnimsTODO.Add(Control.Abe.RUN_1);
            }
            if (name == "JUMPUP")
            {
                AnimsTODO.Add(Control.Abe.JUMPUP);
            }
            if (name == "JUMPDOWN")
            {
                AnimsTODO.Add(Control.Abe.JUMPDOWN);
            }
            if (name == "TURN")
            {
                AnimsTODO.Add(Control.Abe.TURN);
            }

            if (name == "TURNDOWN")
            {
                AnimsTODO.Add(Control.Abe.TURNdOWN);
            }
            if (name == "SNEAK1")
            {
                AnimsTODO.Add(Control.Abe.SNEAK_1);
            }
            if (name == "CROUCH")
            {
                AnimsTODO.Add(Control.Abe.CROUCH);
            }
            if (name == "STANDUP")
            {
                AnimsTODO.Add(Control.Abe.STANDUP);
            }
            if (name == "ROLL1")
            {
                AnimsTODO.Add(Control.Abe.ROLL1);
            }
            if (name == "KO")
            {
                AnimsTODO.Add(Control.Abe.KO);
            }
            if (name == "GETUP")
            {
                AnimsTODO.Add(Control.Abe.GETUP);
            }
            if (name == "BLOCK")
            {
                AnimsTODO.Add(Control.Abe.BLOCK);
            }
            if (name == "HOISTUP")
            {
                AnimsTODO.Add(Control.Abe.HOISTUP);
            }
            if (name == "HOISTDOWN")
            {
                AnimsTODO.Add(Control.Abe.HOISTDOWN);
            }
            if (name == "PLANE")
            {
                AnimsTODO.Add(Control.Abe.PLANE);
            }
            if (name == "HELLO")
            {
                AnimsTODO.Add(Control.Abe.HELLO);
            }
            if (name == "FOLLOW")
            {
                AnimsTODO.Add(Control.Abe.FOLLOW);
            }
            if (name == "WAITME")
            {
                AnimsTODO.Add(Control.Abe.WAITME);
            }
            if (name == "COMMANDJUMP")
            {
                AnimsTODO.Add(Control.Abe.COMMANDJUMP);
            }
            if (name == "COMMANDRUNJUMP")
            {
                AnimsTODO.Add(Control.Abe.COMMANDRUNJUMP);
            }
            if (name == "EXPLODE")
            {
                AnimsTODO.Add(Control.Abe.BOMBEXPLODE);
            }
            if (name == "BOMBACTIVATE")
            {
                AnimsTODO.Add(Control.Abe.BOMBDEACTIVATE);
            }
            if (name == "DIE")
            {
                AnimsTODO.Add(Control.Abe.DIE);
            }
            if (name == "PULLEVER")
            {
                AnimsTODO.Add(Control.Abe.PULLEVER);
            }
        }

        //Metodo chiamato per eseguire tutte le animazioni contenute in un'azione
        public bool DO()
        {
            if (!AnimsTODO[CURRENT_ANIM].LastFrameDone)
            {
                Control.Abe.AnimateAbe(AnimsTODO[CURRENT_ANIM]);
                return false;
            }
            else
            {
                if (CURRENT_ANIM == AnimsTODO.Count - 1)
                {
                    CURRENT_ANIM = 0;
                    Control.CURRENT_STATE.CURRENT_ANIM = 0;
                    return true;
                }
                else
                {
                    CURRENT_ANIM++;
                }
                return false;

            }
        }
        #region Attribute
        public string NAME
        {
            get { return name; }
        } 
        #endregion
    }

    //Contiene i riferimenti a tutte le istanze della classe ACTIONa
    public class ACTIONSa
    {
        AbeControl Control;
        public ACTIONa STOP;
        public ACTIONa STOPSNEAK;
        public ACTIONa PASS1;
        public ACTIONa RUN1;
        public ACTIONa JUMP1;
        public ACTIONa JUMP4;
        public ACTIONa JUMPUP;
        public ACTIONa JUMPDOWN;
        public ACTIONa SNEAK1;
        public ACTIONa TURN;
        public ACTIONa TURNDOWN;
        public ACTIONa CROUCH;
        public ACTIONa STANDUP;
        public ACTIONa ROLL1;
        public ACTIONa BLOCK;
        public ACTIONa HOISTUP;
        public ACTIONa HOISTDOWN;
        public ACTIONa PLANE;
        public ACTIONa HELLO;
        public ACTIONa FOLLOW;
        public ACTIONa WAITME;
        public ACTIONa COMMANDJUMP;
        public ACTIONa COMMANDRUNJUMP;
        public ACTIONa KO;
        public ACTIONa GETUP;
        public ACTIONa DIE;
        public ACTIONa EXPLODE;
        public ACTIONa BOMBACTIVATE;
        public ACTIONa PULLEVER;
        public ACTIONa HUNGLONG;
        public ACTIONa STOPRUNJUMP;

        public ACTIONSa(AbeControl Control)
        {
            this.Control = Control;

            STOP = new ACTIONa(Control, "STOP");
            STOPSNEAK = new ACTIONa(Control, "STOPSNEAK");
            PASS1 = new ACTIONa(Control, "PASS1");
            RUN1 = new ACTIONa(Control, "RUN1");
            SNEAK1 = new ACTIONa(Control, "SNEAK1");
            JUMP1 = new ACTIONa(Control, "JUMP1");
            JUMP4 = new ACTIONa(Control, "JUMP4");
            JUMPUP = new ACTIONa(Control, "JUMPUP");
            JUMPDOWN = new ACTIONa(Control, "JUMPDOWN");
            TURN = new ACTIONa(Control, "TURN");
            TURNDOWN = new ACTIONa(Control, "TURNDOWN");
            CROUCH = new ACTIONa(Control, "CROUCH");
            STANDUP = new ACTIONa(Control, "STANDUP");
            ROLL1 = new ACTIONa(Control, "ROLL1");
            BLOCK = new ACTIONa(Control, "BLOCK");
            HOISTUP = new ACTIONa(Control, "HOISTUP");
            HOISTDOWN = new ACTIONa(Control, "HOISTDOWN");
            PLANE = new ACTIONa(Control, "PLANE");
            HELLO = new ACTIONa(Control, "HELLO");
            FOLLOW = new ACTIONa(Control, "FOLLOW");
            WAITME = new ACTIONa(Control, "WAITME");
            COMMANDJUMP = new ACTIONa(Control, "COMMANDJUMP");
            COMMANDRUNJUMP = new ACTIONa(Control, "COMMANDRUNJUMP");
            KO = new ACTIONa(Control, "KO");
            GETUP = new ACTIONa(Control, "GETUP");
            DIE = new ACTIONa(Control, "DIE");
            PULLEVER = new ACTIONa(Control, "PULLEVER");
            HUNGLONG = new ACTIONa(Control, "HUNGLONG");
            STOPRUNJUMP = new ACTIONa(Control, "STOPRUNJUMP");
            EXPLODE = new ACTIONa(Control, "EXPLODE");
            BOMBACTIVATE = new ACTIONa(Control, "BOMBACTIVATE");


        }

        public ACTIONa AND(ACTIONa action1, ACTIONa action2)
        {
            ACTIONa action = new ACTIONa(Control, "AND");

            foreach (Animation anim in action1.AnimsTODO)
                action.AnimsTODO.Add(anim);
            foreach (Animation anim in action2.AnimsTODO)
                action.AnimsTODO.Add(anim);

            return action;
        }
    }

}
